package com.oracle.coherence.patterns.security.proxy;

import com.oracle.coherence.patterns.security.KrbSecurityHelper;
import com.oracle.coherence.patterns.security.extend.CacheAction;
import com.oracle.coherence.patterns.security.extend.CachePermission;
import com.oracle.coherence.patterns.security.extend.ExtendAccessController;
import com.tangosol.coherence.Component;
import com.tangosol.coherence.component.net.extend.proxy.CacheServiceProxy;
import com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy;

import javax.security.auth.Subject;


/**
 * This class is an extension of the Coherence CacheServiceProxy.
 * <p/>
 * This implmentation overrides the <code>ensureNamedCacheProxy</code>
 * and checks that the Security principal is authorised to access the
 * requested cache by calling the configured {@link ExtendAccessController}.
 * <p/>
 *
 * @author Jonathan Knight
 */
public class SecureCacheServiceProxy extends CacheServiceProxy {

    /**
     * The access controller that will be used to authorise access to Extend caches
     */
    private ExtendAccessController accessController;

    /**
     * Default empty constructor.<p/>
     */
    public SecureCacheServiceProxy() {
    }

    /**
     * A constructor that sets the {@link com.oracle.coherence.patterns.security.extend.ExtendAccessController}
     * that this SecureCacheServiceProxy will use to authorise access to Extend caches.
     * <p/>
     *
     * @param accessController - the {@link com.oracle.coherence.patterns.security.extend.ExtendAccessController} to use
     */
    public SecureCacheServiceProxy(ExtendAccessController accessController) {
        this.accessController = accessController;
    }

    /**
     * Overrides the parent implementation.<p/>
     * After calling the supe class method a check is made to see if
     * the NamedCache returned is an instance of SecureNamedCache.
     * If this is true, a check is made to see if the current security
     * principal can access the cache service.<p/>
     *
     * @param cacheName - the name of the cache to return
     * @return an instance of the specified NamedCache
     */
    @Override
    public NamedCacheProxy ensureNamedCacheProxy(String cacheName) {
        if (accessController != null) {
            Subject subject = KrbSecurityHelper.getCurrentSubject();
            CachePermission permission = new CachePermission(cacheName, CacheAction.GETCACHESERVICE.toString());
            accessController.checkPermission(permission, subject);
        }
        return super.ensureNamedCacheProxy(cacheName);
    }

    /**
     * All Coherence Compaonent classes appear to implement this method.<p/>
     *
     * @return the class of this class.
     */
    public static Class get_CLASS() {
        return SecureCacheServiceProxy.class;
    }

    /**
     * All Coherence Compaonent classes appear to implement this method.<p/>
     *
     * @return a new instance of SecureProxyService.
     */
    public static Component get_Instance() {
        return new SecureCacheServiceProxy();
    }
}